package com.imooc.router.processor;

import com.google.auto.service.AutoService;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.imooc.router.annotations.Destination;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;

/**
 * @author: xiaosy
 * 时间: 2024/11/1
 * @Description: 注解处理器
 * @Version: 1.0
 **/
@AutoService(Processor.class)
public class DestinationProcessor extends AbstractProcessor {
    private static final String TAG = DestinationProcessor.class.getSimpleName();

    @SuppressWarnings("unchecked")
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (roundEnvironment.processingOver()) {
            return false;
        }
        System.out.println(TAG + ">>> process start ...");

        String rootDir = processingEnv.getOptions().get("root_project_dir");
        if (rootDir != null) {
            System.out.println("rootDir = " + rootDir);
        }
        Set<Element> allDestinationElements = (Set<Element>) roundEnvironment.getElementsAnnotatedWith(Destination.class);
        if (allDestinationElements.isEmpty()) {
            return false;
        }
        String className = "RouterMapping_" + System.currentTimeMillis();
        StringBuilder builder = new StringBuilder();
        builder.append("package com.imooc.router.mapping;\n\n");
        builder.append("import java.util.HashMap;\n\n");
        builder.append("import java.util.Map;\n\n");
        builder.append("public class ").append(className).append(" {\n\n");
        builder.append("        public static Map<String, String> get() { \n\n");
        builder.append("            Map<String, String> mapping = new HashMap<>(); \n\n");

        final JsonArray destinationJsonArray = new JsonArray();

        for (Element element : allDestinationElements) {
            final TypeElement typeElement = (TypeElement) element;
            final Destination destination = typeElement.getAnnotation(Destination.class);
            if (destination == null) {
                continue;
            }
            final String url = destination.url();
            final String description = destination.description();
            final String realPath = typeElement.getQualifiedName().toString();
            System.out.println(TAG + ">>> url = " + url);
            System.out.println(TAG + ">>> description = " + description);
            System.out.println(TAG + ">>> realPath = " + realPath);
            builder.append("             ")
                    .append("mapping.put(").append("\"").append(url).append("\"")
                    .append(", ").append("\"").append(realPath).append("\"")
                    .append(");\n");


            JsonObject item = new JsonObject();
            item.addProperty("url", url);
            item.addProperty("description", description);
            item.addProperty("realPath", realPath);
            destinationJsonArray.add(item);
        }
        builder.append("        return mapping;\n");
        builder.append("    }\n");
        builder.append("}\n");

        String mappingFullClassName = "com.imooc.router.mappping." + className;
        System.out.println(TAG + ">>> mappingFullClassName = " + mappingFullClassName);
        System.out.println(TAG + ">>> class content = " + builder);
        try {
            //RouterMapping_xx.java
            JavaFileObject source = processingEnv.getFiler().createSourceFile(mappingFullClassName);
            Writer writer = source.openWriter();
            writer.write(builder.toString());
            writer.flush();
            writer.close();
        } catch (Exception e) {
            throw new RuntimeException("Error while create file", e);
        }
        //rootDir(processor参数值)
        File rootDirFile = new File(rootDir);
        if (!rootDirFile.exists()) {
            throw new RuntimeException("root_project_dir not exist!");
        }
        File routerFileDir = new File(rootDirFile, "router_mapping");
        if (!routerFileDir.exists()) {
            routerFileDir.mkdir();
        }

        File mappingFile = new File(routerFileDir, "mapping_" + System.currentTimeMillis() + ".json");
        try {
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(mappingFile));
            String jsonStr = destinationJsonArray.toString();
            bufferedWriter.write(jsonStr);
            bufferedWriter.flush();
            bufferedWriter.close();
        } catch (Throwable throwable) {
            throw new RuntimeException("Error while writing json", throwable);
        }

        System.out.println(TAG + ">>> all Destination elements count = " + allDestinationElements.size());
        return false;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Collections.singleton(
                Destination.class.getCanonicalName()
        );
    }
}
